package zbl.c0.inter;

import java.util.Enumeration;
import java.util.Scanner;

import zbl.c0.symbol.FuncTable;
import zbl.c0.symbol.Symbol;
import zbl.c0.symbol.SymbolTable;

public class Interpret {
	
	private GlobalStack datastack;		//  数据栈
	
	private CodeStack	codestack;		//  代码栈
	
	private SymbolTable symboltable;	//	符号表
	
	private CalculStack calculstack;	//	运算栈
	
	private StringStack strstack;		//	字符串常量栈
	
	private FuncTable curfunctable;	//  记录当前的函数信息表
	
	private Pcode curOp;			//  当前指令寄存器
	
	private int pc;					//  解释执行器的程序计数器
	
	private int base;				//  当前基址寄存器
	
	private int in;					//	输入缓冲寄存器
	
	public Interpret(GlobalStack datastack, CodeStack codestack
						, SymbolTable symboltable, StringStack strstack){
		this.datastack = datastack;
		this.codestack = codestack;
		this.symboltable = symboltable;
		this.strstack = strstack;
		curfunctable = null;
		calculstack = new CalculStack();
		
		base = datastack.getAddr();		//  初始化当前基地址为数据栈栈顶（因为datastack之前存的全是全局变量的信息）
		pc = 0;
	}
	
	/**
	 * 		开始执行
	 * @return
	 */
	public int execute(){
		
		while(true){
			curOp = codestack.getOp(pc);	//  通过程序计数器获得下一条指令
			pc++;							//  程序计数器加1
			
			
			if(curOp.op.equals("CAL")){		//	执行CAL指令
											//  注意main函数返回和其他函数的处理不同
				int tempbase = base;		//  暂存之前的基地址
				
				curfunctable = symboltable.getfuncByaddr(curOp.a);
											//  获得被调用函数的函数信息表
				
				base = datastack.getAddr();	//	更新当前基地址
				datastack.add(0);			//  添加SL为0
				datastack.add(tempbase);	//	添加DL为之前的base
				datastack.add(pc);			//  添加函数返回地址
				
				
				
				for(int i=0; i<curfunctable.argTable.size(); i++)
					datastack.push();		//  为参数分配存储空间
				
				//System.out.println(curfunctable.argTable.size()+"********");
				
				for(int i=curfunctable.argTable.size()-1; i>-1; i--){
						//进行参数传递由于在CAL语句之前参数都被显式的依次压到了运算栈栈顶，所以现在只需要按照
						//参数的数目和顺序正确的取得即可。由于参数是以栈的形式压入的这里反着取参数即可。
					Symbol arg = (Symbol)curfunctable.argTable.get(i);
					//System.out.println("ArgName: "+arg.name+" at : "+arg.address);
					datastack.modify(base + arg.address, calculstack.gettopEl());
				}
				
				
				//System.out.println(curfunctable.funcname);
				
				Enumeration<Symbol> en = curfunctable.symtable.elements();
											//  遍历函数内符号表
				while(en.hasMoreElements()){
					Symbol sym = (Symbol) en.nextElement(); // 获得符号
					if(sym.type == Symbol.VAR)	//  如果是变量符号则
						datastack.push();		//  为函数内变量分配存储空间
				}
				
				pc = curOp.a;					//  程序计数器指向函数的入口地址
				
			}else if(curOp.op.equals("JPC")){		//	执行JPC指令
				
				if(calculstack.conduct(curOp.l))	//  条件为真，不改变pc，顺序执行
					continue;
				else{								//  条件为假，改变pc，跳转执行
					pc = curOp.a;
					continue;
				}
				
			}
			else if(curOp.op.equals("LIT")){		//	执行LIT指令
				
				calculstack.push(curOp.a);	//  把curOp.a对应的常数送到运算栈栈顶
				
			}
			else if(curOp.op.equals("OPR")){//	执行OPR指令
				
				calculstack.opera(curOp.a);	//	执行curOp.a对应的操作
				
			}
			else if(curOp.op.equals("LOD")){	//	执行LOD指令
				if(curOp.l == 0){		// 函数内部变量
					//	采用基址加变址寻址，把数据栈指定位置的信息读取到运算栈栈顶
					calculstack.push(datastack.get(base + curOp.a));
				}else{		// 全局变量
							// datastack.get(base + 0)静态链地址，此处一定为0
					calculstack.push(datastack.get(datastack.get(base + 0) + curOp.a));
				}
			
			}
			else if(curOp.op.equals("STO")){	//	执行STO指令
				if(curOp.l == 0){	// 函数内部变量
											//	采用基址加变址寻址，把运算栈 的栈顶存到指定为位置
											//栈顶指针  减 1    ？  gettopEl()方法使栈顶指针减1
					datastack.modify(base + curOp.a, calculstack.gettopEl());
				}
				else{				// 全局变量
									// datastack.get(base + 0)静态链地址，此处一定为0
					datastack.modify(datastack.get(base + 0) + curOp.a, calculstack.gettopEl());
					
				}
				
			}else if(curOp.op.equals("RET")){	//	执行RET指令
				//showDataStack();
				//showCalcul();
				
				int tempbase = base;			// 暂存当前基地址，最后要设置数据栈的栈顶指针为当前基地址
				pc = datastack.get(base+ 2);	// 设置pc为函数的返回地址	
				base = datastack.get(base + 1);	// 设置当前基地址为DL所指向的调用当前函数的函数的基地址
				datastack.setTop(tempbase);
				
				if(curOp.a == 0)		//	表示一般函数返回
				{
					continue;
				}else{					//  表示主函数返回，标志着程序的结束！！！
					break;
				}
			}else if(curOp.op.equals("RED")){//	执行RED指令
				
				Scanner x=new Scanner(System.in);//构造一个Scanner对象，其传入参数为System.in 
				in = x.nextInt();				 //从标准输入读取一个整数
				
				if(curOp.l==0){					// 表示函数内的变量
					datastack.modify(base + curOp.a, in);
				}else{							// 全局变量
					datastack.modify(datastack.get(base + 0) + curOp.a, in);
				}
				
			}else if(curOp.op.equals("WRT")){//	执行WRT指令
				
				if(curOp.l == 0){			//l==0  表示输出的是当前运算栈栈顶的元素
					
					System.out.print(calculstack.gettopEl());
				
				}else{						//l==1  表示要输出字符串, a 要输出的字符串在常量串中的位置
					System.out.print(strstack.getStr(curOp.a));
				}
				
			}else if(curOp.op.equals("INT")){//	执行INT指令
											 // 运算栈的栈顶指针减 curOp.a
				
				calculstack.minus(curOp.a);
				
			}
			else{						//  异常终止
				System.out.println("非法指令！！");
				return -1;
			}
			
		}
		
		
		//showCalcul();					//测试用显示程序执行结束后运算栈和全局变量的信息
		//showDataStack();
		return 0;
	}
	
	/**
	 * 		显示代码栈信息
	 */
	public void showCode(){
		codestack.showStack();
	}
	
	/**
	 * 		显示运算栈信息
	 */
	public void showCalcul(){
		calculstack.showStack();
	}
	
	/**
	 * 		显示数据栈信息
	 */
	public void showDataStack(){
		datastack.showStack();
	}
	
	
}
